const webpack = require('webpack')
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
const packageJSON = require('./package.json')
const variables = require('./webpack.variables')

const resolve = dir => path.join(__dirname, './', dir)
const resolveEntry = dir => ['core-js/stable', 'regenerator-runtime/runtime', resolve(dir)]
const capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperCase())
const capitalizeTitle = (title = packageJSON.name) => capitalizeEveryWord(title.toLowerCase().replace(/_/g, ' '))
const entry = `chunk-${packageJSON.name.toLocaleLowerCase().replace(/_/g, '-')}`

let config = {
  entry: {
    [entry]: resolveEntry('src/app.js')
  },
  module: {
    rules: [
      {
        test: /\.s?[ac]ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              esModule: false
            }
          },
          {
            loader: 'css-loader',
            options: {
              esModule: false
            }
          },
          {
            loader: 'sass-loader',
            options: {
              additionalData: `$debug: ${variables.EXT_DEBUG_MODE};`
            }
          }
        ]
      },
      {
        test: [/\.vert$/, /\.frag$/],
        use: 'raw-loader'
      },
      {
        test: /\.(png|jpe?g|gif|svg|xml)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              name(resourcePath) {
                if (/assets[/\\]images/.test(resourcePath)) {
                  const folder = resourcePath
                    .split(/assets[/\\]images[/\\]/)
                    .pop()
                    .split(/[/\\]/)
                    .slice(0, -1)
                    .join('/')

                  if (folder) {
                    return `${folder}/[name].[ext]`
                  }
                }

                return '[name].[ext]'
              },
              outputPath: 'images'
            }
          }
        ]
      },
      {
        test: /\.(woff2)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name].[ext]',
              outputPath: 'fonts'
            }
          }
        ]
      },
      {
        test: /\.(mp3)$/i,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name].[ext]',
              outputPath: 'audio'
            }
          }
        ]
      },
      {
        test: /\.js$/,
        exclude: /(obfuscator|node_modules)/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.js$/,
        include: /obfuscator/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'javascript-obfuscator-loader',
            options: {
              level: 2
            }
          },
          {
            loader: 'babel-loader'
          }
        ]
      }
    ]
  },
  performance: {
    maxEntrypointSize: 900000,
    maxAssetSize: 900000
  },
  resolveLoader: {
    modules: [resolve('webpack/loaders'), 'node_modules']
  },
  resolve: {
    alias: {
      '@': resolve('src/')
    }
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].css'
    }),
    new HtmlWebpackPlugin({
      title: capitalizeTitle(),
      template: resolve('public/index.html'),
      filename: 'index.html',
      chunks: 'all',
      cache: false
    }),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public',
          to: resolve('dist'),
          filter: resourcePath => !/index.html$/.test(resourcePath),
          force: true,
          transform: (content, absoluteFrom) => {
            if (/manifest.json$/.test(absoluteFrom)) {
              const manifest = content.toString()
              return manifest
                .replace(/<%= package.name %>/g, capitalizeTitle())
                .replace(/<%= package.version %>/g, packageJSON.version)
            }

            return content
          }
        },
        {
          from: 'src/assets/maps',
          to: resolve('dist/maps')
        }
      ]
    }),
    new webpack.DefinePlugin({
      'process.env': {
        ...Object.keys(variables).reduce((accumulator, currentValue) => {
          accumulator[currentValue] = JSON.stringify(variables[currentValue])
          return accumulator
        }, {})
      }
    })
  ]
}

module.exports = (env, argv) => {
  config = {
    ...config,
    output: {
      path: resolve(variables.EXT_OUTPUT_FOLDER),
      filename:
        process.env.NODE_ENV === 'development'
          ? 'javascript/[name].js'
          : 'javascript/chunk-[fullhash:8][chunkhash:8].min.js'
    },
    mode: process.env.NODE_ENV,
    optimization: {
      minimize: process.env.NODE_ENV === 'production',
      minimizer: [
        new TerserPlugin({
          terserOptions: {
            mangle: {
              properties: {
                regex: /^(\$|mangled)/
              }
            },
            compress: {
              drop_console: !variables.EXT_DEBUG_MODE
            }
          },
          extractComments: variables.EXT_DEBUG_MODE
        })
      ],
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          node_vendors: {
            name: 'chunk-libs',
            chunks: 'initial',
            test: /[\\/]node_modules[\\/]/,
            priority: 10
          },
          node_phaser: {
            name: 'chunk-phaser',
            priority: 20,
            test: /[\\/]node_modules[\\/]_?phaser(.*)/
          }
        }
      }
    }
  }

  if (process.env.NODE_ENV === 'development') {
    config = {
      ...config,
      devtool: 'inline-source-map',
      devServer: {
        client: {
          overlay: false
        },
        static: {
          directory: resolve('')
        },
        devMiddleware: { writeToDisk: false },
        allowedHosts: 'all',
        port: variables.EXT_SERVER_PORT,
        host: '0.0.0.0',
        hot: true,
        liveReload: true
      }
    }
  }

  if (process.env.NODE_ENV === 'production') {
    config.plugins.push(
      new CleanWebpackPlugin({
        verbose: true,
        cleanStaleWebpackAssets: true,
        cleanOnceBeforeBuildPatterns: ['**/*']
      })
    )
  }

  if (argv.analyze) {
    config.plugins.push(new BundleAnalyzerPlugin())
  }

  return config
}
